﻿package com.videointeractive.manager
{
	import flash.display.Sprite;
	import flash.display.Shape;
	import flash.display.DisplayObject;
	
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.events.NetStatusEvent;
	import flash.events.ActivityEvent;
	import flash.events.AsyncErrorEvent;
	import flash.events.StatusEvent;
	import flash.events.MouseEvent;
	
	import fl.transitions.Transition;
	import fl.transitions.TweenEvent;
	
	import fl.video.*;
	
	import flash.system.Security;
	import flash.system.SecurityPanel;
	
	import flash.net.NetConnection;
	import flash.net.NetStream;
	
	import flash.media.Video;
	import flash.media.Microphone;
		
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.text.AntiAliasType;
	
	import flash.utils.Timer;
	
	import fl.transitions.Tween;
	import fl.transitions.easing.*;
	
	import com.videointeractive.conf.VideoSequencesConf;
	import com.videointeractive.conf.VideoDesignConf;
	
	import com.videointeractive.tool.FontLoader;	
	import com.videointeractive.tool.VideoTrackBar;
	
	import com.videointeractive.tool.GraphicLoader;
	import com.videointeractive.tool.notification.GraphicEvent;
	
	import com.videointeractive.util.TextFieldUtil;
	
	import com.videointeractive.vo.ElementGraphicVO;
	
	public class VideoManager extends Sprite
	{
		private var _video 				: Video;
		private var _stream				: NetStream;
		private var _positionText		: TextField;
		private var _instructionText	: TextField;
		private var _instructionRect	: Shape;
		private var _instructionRectTween	: Tween;
		private var _instructionTextTween	: Tween;
		private var _duration			: uint = 0;
		private var _timer				: Timer;
		private var _currentCuePoint	: Number;
		private var _microphone			: Microphone;
		private var _tolerance			: Number = 0;
		private var _cuePointsArray		: Array = new Array();
		private var _isPlaying			: Boolean = false;
		
		private var _isWarned			: Boolean = false;
		private var _isTweenPlaying		: Boolean = false;
		private var _hasGameScreen		: Boolean = false;
		
		private var _gameScreenShape	: Shape;
		private var _gameScreenTextField: TextField;
		
		private var _resetButton		: ResetButton;
		private var _trackBar			: VideoTrackBar;
		
		private var _failurePicture		: Failure;
		private var _successPicture		: Success;
		private var _warningPicture		: Warning;
		
		private var _warningPicTween	: Tween;
		private var _isWarningPeriod	: Boolean = false;
		
		private var _loaderCount		: uint = 0;
		
		private static const INSTRUCTION_BUFFERING : String = "veuillez patienter pendant le chargement";
		
		// le constructeur
		public function VideoManager ( )
		{
			_failurePicture = new Failure( );
			_successPicture	= new Success( );
			_warningPicture = new Warning( );
			
			_resetButton = new ResetButton( );
			_resetButton.x = VideoDesignConf.BUTTON_DEFAULT_POSITION_X;
			_resetButton.y = VideoDesignConf.BUTTON_DEFAULT_POSITION_Y;
						
			_instructionText = new TextField();
			_positionText = new TextField();
			
			_instructionRect = new Shape( );
			
			_instructionRect.graphics.beginFill( 0xFFFFFF );
			_instructionRect.graphics.drawRoundRect( 
														VideoDesignConf.INSTRUCTION_RECT_X,
														VideoDesignConf.INSTRUCTION_RECT_Y, 
														VideoDesignConf.INSTRUCTION_RECT_WIDTH,
														VideoDesignConf.INSTRUCTION_RECT_HEIGHT, 
														VideoDesignConf.INSTRUCTION_RECT_ELLIPSE,
														VideoDesignConf.INSTRUCTION_RECT_ELLIPSE
														);
			_instructionRect.graphics.endFill();
			
			_warningPicture.x 		= VideoDesignConf.VIDEO_DEFAULT_POSITION_X + VideoDesignConf.VIDEO_DEFAULT_WIDTH + VideoDesignConf.PADDING_VIDEO_TO_PICTO_X;
			_warningPicture.y		= VideoDesignConf.VIDEO_DEFAULT_POSITION_Y + VideoDesignConf.VIDEO_DEFAULT_HEIGHT + VideoDesignConf.PADDING_VIDEO_TO_PICTO_Y;
			_warningPicture.width	= VideoDesignConf.PICTO_VALUE;
			_warningPicture.height	= VideoDesignConf.PICTO_VALUE;
			
			_successPicture.x		= VideoDesignConf.VIDEO_DEFAULT_POSITION_X + ( VideoDesignConf.VIDEO_DEFAULT_WIDTH / 2 ) - ( VideoDesignConf.PICTO_VALUE / 2 );
			_successPicture.y		= VideoDesignConf.VIDEO_DEFAULT_POSITION_Y + ( ( VideoDesignConf.VIDEO_DEFAULT_HEIGHT / 3 ) * 2 );
			_successPicture.width	= VideoDesignConf.PICTO_VALUE;
			_successPicture.height	= VideoDesignConf.PICTO_VALUE;
			
			_failurePicture.x		= VideoDesignConf.VIDEO_DEFAULT_POSITION_X + ( VideoDesignConf.VIDEO_DEFAULT_WIDTH / 2 ) - ( VideoDesignConf.PICTO_VALUE / 2 );
			_failurePicture.y		= VideoDesignConf.VIDEO_DEFAULT_POSITION_Y + ( ( VideoDesignConf.VIDEO_DEFAULT_HEIGHT / 3 ) * 2 );			
			_failurePicture.width	= VideoDesignConf.PICTO_VALUE;
			_failurePicture.height	= VideoDesignConf.PICTO_VALUE;
			
			_failurePicture.visible = false;
			_successPicture.visible = false;
			_warningPicture.visible = false;
			
			addChild( _instructionRect );
			addChild( _warningPicture );
			
			TextFieldUtil.formatTextField( 
							_instructionText,
							TextFieldAutoSize.LEFT,
							0x000000,
							VideoDesignConf.INSTRUCTION_TEXT_X,
							VideoDesignConf.INSTRUCTION_TEXT_Y,
							INSTRUCTION_BUFFERING
							);
			TextFieldUtil.formatTextField(
							_positionText,
							TextFieldAutoSize.LEFT,
							0x000000,
							VideoDesignConf.POSITION_TEXT_X,
							VideoDesignConf.POSITION_TEXT_Y
							);
			_timer = new Timer(1000);
			_timer.addEventListener( TimerEvent.TIMER, onTimer );
			_timer.start();
			
			_trackBar = new VideoTrackBar( VideoManager( this ), 0x990000, 0x333333 );
		}
		
		public function loadFLV ( urlFLV : String ) : void
		{
			_video = new Video( ); // jouée en 320 x 261 à cause de l'export..
			
			var connection : NetConnection = new NetConnection( );
			connection.connect( null ); // null == nomConnexion
			
			_stream = new NetStream( connection );
			_stream.play( urlFLV );
			_stream.togglePause();
			
			var client : Object = new Object( );
			client.onMetaData = onMetaData;
			client.onCuePoint = cuePointHandler;
			_stream.client = client;
			
			_video.attachNetStream( _stream );
			
			_stream.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
			_stream.addEventListener( AsyncErrorEvent.ASYNC_ERROR, onAsyncError );
			
			_microphone = Microphone.getMicrophone();
			
			Security.showSettings(SecurityPanel.MICROPHONE);
			
			_microphone.setLoopBack(true);
			_microphone.setUseEchoSuppression(true);
			
			addChild( _video );
			addChild( _instructionText );
			addChild( _positionText );
			addChild( _resetButton );
			
			_resetButton.addEventListener( MouseEvent.CLICK, resetVideo );
		}
		
		public function playFLV ( ) : void
		{
			_stream.togglePause();				
			_isPlaying		= ! _isPlaying;
		}
		
		public function resetVideo ( pEvt : MouseEvent = null ) : void
		{
			goTo( VideoSequencesConf.INITIAL_IDLE_PERIOD );
			
			if ( ! _isPlaying )
				playFLV( );
				
			if ( hasGameScreen )
			{
				_gameScreenShape.graphics.clear();
				
				_gameScreenShape.visible = false;
				_gameScreenTextField.visible = false;
				
				_successPicture.visible = false;
				_failurePicture.visible = false;
				
				_hasGameScreen = false;
			}
			
			trackbar.trigger_updateFrontShape( );
		}
		
		private function onMetaData( data : Object ) : void
		{
			_duration = data.duration;
			for ( var prop : * in data.cuePoints )
			{
				_cuePointsArray.push( data.cuePoints[ prop ] );
			}			
		}
		
		private function onNetStatus ( pEvt : NetStatusEvent ) : void
		{
			if( ! isPlaying )
				_instructionText.text = VideoSequencesConf.LOAD_SENTENCE_SUCCESS;
			
			_video.width	= _video.videoWidth;
			_video.height	= _video.videoHeight;
			
			_video.x		= VideoDesignConf.VIDEO_DEFAULT_POSITION_X;
			_video.y		= VideoDesignConf.VIDEO_DEFAULT_POSITION_Y;
			
			_trackBar.x = VideoDesignConf.TRACKBAR_DEFAULT_POSITION_X;
			_trackBar.y = VideoDesignConf.TRACKBAR_DEFAULT_POSITION_Y;
			
			for ( var i : uint = 0 ; i < this.parent.numChildren ; i ++ )
			{
				if ( this.parent.getChildByName( _trackBar.name ) ) return;
			}
			
			addChild( _trackBar );
		}
		
		private function onAsyncError ( pEvt : AsyncErrorEvent ) : void
		{
			_instructionText.text = VideoSequencesConf.LOAD_SENTENCE_ERROR;
		}
		
		private function onTimer ( pEvt : TimerEvent ) : void
		{
			if ( _duration > 0 && _stream.time > 0 )
				_positionText.text = Math.round( _stream.time ) + " / " + Math.round( _duration );
		}
		
		private function startWarningPeriod ( ) : void
		{
			_microphone.setSilenceLevel( _tolerance );
			stage.addEventListener( Event.ENTER_FRAME, checkSilenceLevel );
			_warningPicture.visible = true;
			
			isWarningPeriod = true;
		}
		
		private function checkSilenceLevel( pEvt : Event ) : void
		{
			if ( ( _microphone.activityLevel != -1 ) && ( _microphone.activityLevel > _tolerance ) )
				isWarned = true;
		}
		
		private function stopCheckingSilenceLevel ( ) : void
		{
			_microphone.setSilenceLevel( 100 );
			stage.removeEventListener( Event.ENTER_FRAME, checkSilenceLevel );
		}
		
		private function goTo( cueName : String ) : void
		{
			var cueTime : Number = getTimeByName( cueName );
			getObjectByName( cueName );
			_stream.seek( cueTime );
			if ( cueTime == -1 )
				trace("le cueTime est erroné");
		}
		
		private function getTimeByName ( cueName : String ) : Number
		{
			for ( var i : uint ; i < _cuePointsArray.length ; i ++ )
			{
				if ( _cuePointsArray[ i ].name == cueName )
					return _cuePointsArray[ i ].time;
			}
			
			return -1;
		}
		
		private function getObjectByName ( cueName : String ) : void
		{
			for ( var i : uint ; i < _cuePointsArray.length ; i ++ )
			{
				if ( _cuePointsArray[ i ].name == cueName )
				{
					cuePointHandler( _cuePointsArray[ i ] );
					trace("getObjectByName -- " + cueName );
					return;
				}
			}
			
			trace("il y a eu une erreur : " + cueName );
		}
		
		private function showGameScreen( success : Boolean = false ) : void
		{
			if ( ! _gameScreenShape )
			{
				_gameScreenShape = new Shape ( );
				_gameScreenShape.name = "gameScSHP";
				addChild( _gameScreenShape );
			}
			else _gameScreenShape.visible = true;
			
			_gameScreenShape.graphics.beginFill ( 0x000000 );			
			_gameScreenShape.graphics.drawRect( VideoDesignConf.VIDEO_DEFAULT_POSITION_X, VideoDesignConf.VIDEO_DEFAULT_POSITION_Y, 320, 261 );
			_gameScreenShape.graphics.endFill();
			
			if ( ! _gameScreenTextField )
			{
				_gameScreenTextField = new TextField( );
				_gameScreenTextField.name = "gameScTXT";
				addChild( _gameScreenTextField );
			}
			else _gameScreenTextField.visible = true;
			
			var gameMessage : String = ( success ) ? VideoSequencesConf.HUMOUR_WINNER_SENTENCE : VideoSequencesConf.HUMOUR_GAMEOVER_SENTENCE;
					
			TextFieldUtil.formatTextField( 
							_gameScreenTextField,
							TextFieldAutoSize.LEFT,
							0xFFFFFF,
							VideoDesignConf.VIDEO_DEFAULT_POSITION_X + 30,
							VideoDesignConf.VIDEO_DEFAULT_POSITION_Y + 90,
							gameMessage
							);
						
			if ( success )
			{
				if ( getChildByName( _successPicture.name ) == null )
					addChild( _successPicture );
				
				_successPicture.visible = true;
			}
			else
			{
				if ( getChildByName( _failurePicture.name ) == null )
					addChild( _failurePicture );
				
				_failurePicture.visible = true;
			}
			
			_hasGameScreen = true;
		}
		
		private function tweenInteractivity( pEvt : TweenEvent ) : void
		{
			if ( pEvt.type == TweenEvent.MOTION_CHANGE )
				_isTweenPlaying = true;
			else if ( pEvt.type == TweenEvent.MOTION_FINISH )
				_isTweenPlaying = false;
		}
		
		private function showInstructionCG ( ) : void
		{
			_instructionRect.visible = true;
		}
		
		private function hideInstructionCG ( ) : void
		{
			_instructionRect.visible = false;
		}
		
		private function idleInteractivity ( pEvt : Object ) : void
		{
			trace("idle - cuepoint interaction - " + pEvt.name);
			
			stopCheckingSilenceLevel();
			
			trace("idleInteractivity : isWarned est égal à "+ _isWarned );
			
			if ( ! isWarned )
			{
				playFLV( );
				showGameScreen( );
				
				if ( ! _instructionRect.visible )
					showInstructionCG ( );
				
				_instructionText.text = VideoSequencesConf.LOAD_SENTENCE_TRYAGAIN;
			}
		}
		
		private function warningInteractivity ( pEvt : Object, pTolerance : Number = 40 ) : void
		{
			trace("warning - cuepoint interaction - " + pEvt.name);
			
			_tolerance = pTolerance;
			isWarned = false;
			startWarningPeriod( );
		}
		
		private function safeInteractivity ( pEvt : Object, jump : String ) : void
		{
			trace("safe - cuepoint interaction - " + pEvt.name);
			
			isWarningPeriod = false;
			
			if ( ! isWarned )
			{
				stopCheckingSilenceLevel();
				goTo( jump );
			}
		}
		
		private function hurtInteractivity ( pEvt : Object, jump : String ) : void
		{
			trace("hurt - cuepoint interaction - " + pEvt.name);
			
			if ( isWarned )
			{
				goTo( jump );
			}
		}
		
		private function cuePointHandler( pEvt : Object ) : void
		{
			if ( pEvt.parameters['text'] == "..." )
			{
				hideInstructionCG();
				_instructionText.text = '';
			}
			else
			{
				showInstructionCG();
				_instructionText.text = pEvt.parameters['text'];
			}
			
			////////////////////////////////////////////////////
			switch( pEvt.name )
			{
				////////////////////////////////////////////
				////////////////////////////////////////////
				case VideoSequencesConf.INITIAL_IDLE_PERIOD:
				////////////////////////////////////////////	
				trace("idle - cuepoint interaction - " + pEvt.name);
				stopCheckingSilenceLevel();
				isWarned = false;
				////////////////////////////////////////////
				break;
				
				////////////////////////////////////////////
				////////////////////////////////////////////
				////////////////////////////////////////////
				////////////////////////////////////////////
				case VideoSequencesConf.INITIAL_WARNING_PERIOD:
				////////////////////////////////////////////
				warningInteractivity( pEvt );
				////////////////////////////////////////////
				break;
				
				case VideoSequencesConf.INITIAL_SAFE_PERIOD:
				////////////////////////////////////////////
				safeInteractivity( pEvt, VideoSequencesConf.INITIAL_HURT_PERIOD );
				////////////////////////////////////////////
				break;
				
				case VideoSequencesConf.INITIAL_HURT_PERIOD:
				////////////////////////////////////////////
				hurtInteractivity( pEvt, VideoSequencesConf.INTERMEDIATE_IDLE_PERIOD );
				////////////////////////////////////////////
				break;
				
				case VideoSequencesConf.INTERMEDIATE_IDLE_PERIOD:
				////////////////////////////////////////////
				idleInteractivity( pEvt );
				////////////////////////////////////////////
				break;
				////////////////////////////////////////////
				////////////////////////////////////////////
				////////////////////////////////////////////
				////////////////////////////////////////////
				case VideoSequencesConf.INTERMEDIATE_WARNING_PERIOD:
				////////////////////////////////////////////
				warningInteractivity( pEvt, 60 );
				////////////////////////////////////////////
				break;
				
				case VideoSequencesConf.INTERMEDIATE_SAFE_PERIOD:
				////////////////////////////////////////////
				safeInteractivity( pEvt, VideoSequencesConf.INTERMEDIATE_HURT_PERIOD );
				////////////////////////////////////////////
				break;
				
				case VideoSequencesConf.INTERMEDIATE_HURT_PERIOD:
				////////////////////////////////////////////
				hurtInteractivity( pEvt, VideoSequencesConf.FINAL_IDLE_PERIOD );
				////////////////////////////////////////////
				break;
				////////////////////////////////////////////
				////////////////////////////////////////////
				case VideoSequencesConf.FINAL_IDLE_PERIOD:
				////////////////////////////////////////////
				idleInteractivity( pEvt );
				////////////////////////////////////////////
				break;
				////////////////////////////////////////////
				////////////////////////////////////////////
				case VideoSequencesConf.JUMP_PERIOD:
				////////////////////////////////////////////
				trace("jump ! cuepoint interaction");
				if ( !isWarned )
				{
					playFLV( );
					showGameScreen( );
					goTo( VideoSequencesConf.INITIAL_IDLE_PERIOD );
				}
				else
				{
					playFLV( );
					showGameScreen( true );
					goTo( VideoSequencesConf.INITIAL_IDLE_PERIOD );
				}
				////////////////////////////////////////////
				break;
				////////////////////////////////////////////
				////////////////////////////////////////////
				case VideoSequencesConf.FINAL_WARNING_PERIOD:
				////////////////////////////////////////////
				warningInteractivity( pEvt, 80 );
				////////////////////////////////////////////
				break;
				
				case VideoSequencesConf.FINAL_SAFE_PERIOD:
				////////////////////////////////////////////
				//isWarned = true;
				safeInteractivity( pEvt, VideoSequencesConf.FINAL_HURT_PERIOD );
				////////////////////////////////////////////
				break;
				
				case VideoSequencesConf.FINAL_HURT_PERIOD:
				////////////////////////////////////////////
				trace("hurt - cuepoint interaction - "+ pEvt.name );
				trace("a ce stade : "+ _isWarned );
				if ( isWarned )
				{
					goTo( VideoSequencesConf.JUMP_PERIOD );
				}
				////////////////////////////////////////////
				break;
				////////////////////////////////////////////
				////////////////////////////////////////////
			}
		}
		
		public function get isWarned ( ) : Boolean
		{
			return _isWarned;
		}
		
		public function set isWarned ( val : Boolean ) : void
		{
			_isWarned = val;
			if ( val )
			{
				trace("he is warned");
				stopCheckingSilenceLevel( );
			}
			else trace("la on set isWarned à FALSE");
		}
		
		// SHORTCUTS TO VIDEOMANAGER COMPONENTS
		
		public function get duration ( ) : uint
		{
			return _duration;
		}
		
		public function get video ( ) : Video
		{
			return _video;
		}
		
		public function get stream ( ) : NetStream
		{
			return _stream;
		}
		
		public function get trackbar ( ) : VideoTrackBar
		{
			return _trackBar;
		}
		
		public function get button ( ) : ResetButton
		{
			return _resetButton;
		}
		
		// SHORTCUTS TO COMPONENT STATE
		
		public function get isPlaying ( ) : Boolean
		{
			return _isPlaying;
		}
		
		public function get isTweenPlaying ( ) : Boolean
		{
			return _isTweenPlaying;
		}
		
		public function get hasGameScreen ( ) : Boolean
		{
			return _hasGameScreen;
		}
		
		private function set isWarningPeriod ( val : Boolean ) : void
		{
			if ( val )
				_warningPicture.visible = true;
			else
				_warningPicture.visible = false;
			
			_isWarningPeriod = val;
		}
		
		private function get isWarningPeriod ( ) : Boolean
		{
			return _isWarningPeriod;
		}
	}
}